import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;

public class NioHttpServer implements Runnable {

	private static final int DEFAULT_SELECT_TIMEOUT = 100;
    private static volatile boolean running = true;
    private int port;

	private ServerSocketChannel serverSocketChannel;
	private Selector selector;

	public NioHttpServer(int port) {
		this.port = port;
	}

	@Override
	public void run() {
		try {

            selector = Selector.open();
			// create chanel
            serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.configureBlocking(false);
			//bind server socket
            serverSocketChannel.socket().bind(new InetSocketAddress(port));
			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

			while (running) {
				selector.select(DEFAULT_SELECT_TIMEOUT);
				Set<SelectionKey> selectedKeys = selector.selectedKeys();
				for (SelectionKey selectionKey : selectedKeys) {
					try {
						if (selectionKey.isAcceptable())
							accept();
						if (selectionKey.isReadable())
							read(selectionKey);
					} catch (IOException e) {
                        selectionKey.cancel();
                        e.printStackTrace();
					}
				}
				selectedKeys.clear();
			}
		} catch (IOException e) {
			throw new RuntimeException("Server error", e);
		} finally {
			try {
				selector.close();
				serverSocketChannel.close();
			} catch (IOException e) {
                e.printStackTrace();
			}
			running = false;
		}
	}

	private void accept() throws IOException {
		SocketChannel socketChannel = serverSocketChannel.accept();
		socketChannel.configureBlocking(false);
		SelectionKey selectionKey
                = socketChannel.register(selector, SelectionKey.OP_READ);
		selectionKey.attach(ByteBuffer.allocate(1024));
	}

	private void read(SelectionKey selectionKey) throws IOException {
		SocketChannel channel = (SocketChannel) selectionKey.channel();
		ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
		
		while (channel.read(buffer) != -1) {
            buffer.flip();
            while (buffer.hasRemaining()) {
                System.out.print((char) buffer.get());
            }
            buffer.clear();
        }
	}

}
